import functools
from datetime import datetime

import pytz

TZ_SH = pytz.timezone("Asia/Shanghai")

DATE_FORMAT = '%Y-%m-%d'
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
DATETIME_MS_FORMAT = '%Y-%m-%d %H:%M:%S.%f'
TIME_FORMAT = '%H:%M:%S'
TIME_MS_FORMAT = '%H:%M:%S.%f'
ISO_FORMAT = '%Y-%m-%dT%H:%M:%S'
ECHARTS_FORMAT = '%Y-%m-%d %H:%M'

DOOMSDAY = datetime(3000, 1, 1)


class Datetime:
    @classmethod
    def today(cls):
        now = cls.now()
        return datetime(now.year, now.month, now.day)

    @classmethod
    def now(cls):
        return datetime.now()

    @classmethod
    def strptime(cls, _date):
        if isinstance(_date, datetime):
            return _date
        _date = _date.split('.')[0]
        if ' ' in _date:
            _date = datetime.strptime(_date, DATETIME_FORMAT)
        elif 'T' in _date:
            _date = datetime.strptime(_date, ISO_FORMAT)
        else:
            _date = datetime.strptime(_date, DATE_FORMAT)
        return _date

    @classmethod
    def strftime(cls, _date):
        return _date.strftime(DATETIME_FORMAT)

    @classmethod
    def before_trading(cls):
        return datetime.now().replace(hour=9, minute=0, second=0, microsecond=0)

    @classmethod
    def end_trading(cls):
        return datetime.now().replace(hour=15, minute=0, second=6, microsecond=0)

    @classmethod
    def is_trading_start(cls):
        return cls.before_trading() < cls.now() < cls.end_trading()

    @classmethod
    def is_trading_time(cls):
        now = cls.now()
        if now < cls.before_trading() \
                or now.hour == 9 and 26 < now.minute < 29 \
                or now.hour == 11 and now.minute > 30 \
                or now.hour == 12 and now.minute < 59 \
                or now > cls.end_trading():
            return False
        return True

    @classmethod
    def remain_trade_seconds(cls):
        now = cls.now()
        return int((now.replace(hour=18) - now).total_seconds())

    @classmethod
    def time_diff(cls, t1, t2):
        seconds = (t1 - t2).total_seconds()
        if t1.hour == t2.hour == 9 and t1.minute > 29 > t2.minute:
            seconds = seconds > 300 and seconds - 300 or 0
        elif t1.hour > 12 > t2.hour:
            seconds -= 5400
        return seconds


def trading_time(func):
    @functools.wraps(func)
    def wrap(*args, **kwargs):
        if Datetime.is_trading_time():
            return func(*args, **kwargs)

    return wrap
